/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package algoritmo;

import java.util.ArrayList;
import java.util.List;

/**
 * Es el algoritmo genérico, sin ningún tipo de problema en específico, solo sabemos
 * que son nodos. También, sin nungún tipo de agenda en específico, sólo sabemos que 
 * debe haber metodos que nos devuelvan el siguiente nodo.
 * 
 */
public abstract class AbstractSearch {

    /**
     * Nodo inicial
     */
    protected Node start;
    /**
     * Nodo al que se quiere llegar
     */
    protected Node goal;
    /**
     * Resultado de la búsqueda. En este nodo estará toda la ruta que se generó
     */
    protected Node result;
    /**
     * Lista de nodos que ya fueron expandidos
     */
    protected List<Node> closed = new ArrayList<>();

    /**
     * Ejecuta la búsqeda, usando los campos start y goal. 
     * Almacena en la ruta encontrada en el campo result.
     * @return el nodo resultado, que contiene toda la ruta. Si no encontró
     * una solución este nodo será null.
     */
    public Node search() {
        Node n = null;
        result = null;
        n = start;
        closed.clear();
        do {
            if (n.equals(goal)) {
                result = n;
                return result;
            } else {
                if (shouldExpand(n)) {
                    for (Node child : n.expand()) {
                        agendaAdd(child);
                    }
                }
                closed.add(n);
            }
            do {
                n = agendaNextState();
            } while (closed.contains(n));
        } while (n != null);
        return result;
    }

    /**
     * Obtiene el siguiente nodo a explorar
     * @return El siguiente nodo que debe ser expandido o null si ya no hay
     * ninguno
     */
    public abstract Node agendaNextState();

    /**
     * Agrega un nodo a la agenda
     * @param n El nodo que debe ser agregado a la agenda
     */
    public abstract void agendaAdd(Node n);

    /**
     * Determina si el nodo n debe ser expandido. Si no se sobreescribe se considera 
     * que todos los nodos deben ser expandidos
     * @param n El nodo
     * @return true si debe ser expandido
     */
    public boolean shouldExpand(Node n){
        return true;
    }

    public Node getResult() {
        return result;
    }

    public void setGoal(Node goal) {
        this.goal = goal;
    }

    public void setStart(Node start) {
        this.start = start;
    }
    
   

    public List<Node> getClosed() {
        return closed;
    }
    
   
  
    
}
